using System;
using System.Collections.Generic;
using System.Linq;

namespace WenYu.Runtime
{
    /// <summary>
    /// 执行上下文 - 管理运行时的执行状态
    /// 
    /// 功能:
    /// - 操作数栈(用于表达式求值)
    /// - 调用栈(用于函数调用，MVP中不用)
    /// - 全局变量存储
    /// - 当前指令指针
    /// 
    /// 对标需求: REQ-05 标准库接口
    /// </summary>
    public class ExecutionContext
    {
        /// <summary>操作数栈(用于表达式求值)</summary>
        private readonly Stack<Value> _operandStack = new();

        /// <summary>调用栈(函数调用，MVP中预留)</summary>
        private readonly Stack<StackFrame> _callStack = new();

        /// <summary>全局变量存储</summary>
        private readonly Dictionary<string, Value> _globals = new();

        /// <summary>当前执行的指令索引</summary>
        public int InstructionPointer { get; set; } = 0;

        /// <summary>是否正在执行</summary>
        public bool IsRunning { get; set; } = true;

        /// <summary>最后一次返回值(函数调用用)</summary>
        public Value? LastReturnValue { get; set; }

        // ===== 操作数栈操作 =====

        /// <summary>
        /// 压入值到操作数栈
        /// </summary>
        public void PushOperand(Value value)
        {
            if (value == null)
                throw new ArgumentNullException(nameof(value));
            _operandStack.Push(value);
        }

        /// <summary>
        /// 从操作数栈弹出值
        /// </summary>
        /// <exception cref="InvalidOperationException">栈为空</exception>
        public Value PopOperand()
        {
            if (_operandStack.Count == 0)
                throw new InvalidOperationException("操作数栈为空");
            return _operandStack.Pop();
        }

        /// <summary>
        /// 查看操作数栈顶(不弹出)
        /// </summary>
        /// <exception cref="InvalidOperationException">栈为空</exception>
        public Value PeekOperand()
        {
            if (_operandStack.Count == 0)
                throw new InvalidOperationException("操作数栈为空");
            return _operandStack.Peek();
        }

        /// <summary>
        /// 弹出两个操作数(用于二元运算)
        /// </summary>
        /// <returns>(左操作数, 右操作数) - 注意顺序!</returns>
        /// <exception cref="InvalidOperationException">栈中操作数不足</exception>
        public (Value Left, Value Right) PopTwoOperands()
        {
            if (_operandStack.Count < 2)
                throw new InvalidOperationException("操作数栈中操作数不足");
            
            // 栈是LIFO，所以先弹出的是右操作数
            var right = _operandStack.Pop();
            var left = _operandStack.Pop();
            return (left, right);
        }

        /// <summary>
        /// 获取操作数栈中的元素个数
        /// </summary>
        public int OperandStackSize => _operandStack.Count;

        /// <summary>
        /// 清空操作数栈
        /// </summary>
        public void ClearOperandStack()
        {
            _operandStack.Clear();
        }

        /// <summary>
        /// 获取操作数栈的快照(调试用)
        /// </summary>
        public List<Value> OperandStackSnapshot()
        {
            var list = _operandStack.ToList();
            list.Reverse();
            return list;
        }

        // ===== 全局变量操作 =====

        /// <summary>
        /// 设置全局变量
        /// </summary>
        public void SetGlobal(string varName, Value value)
        {
            if (string.IsNullOrEmpty(varName))
                throw new ArgumentException("变量名不能为空", nameof(varName));
            
            if (value == null)
                throw new ArgumentNullException(nameof(value));

            _globals[varName] = value;
        }

        /// <summary>
        /// 获取全局变量
        /// </summary>
        /// <exception cref="KeyNotFoundException">变量不存在</exception>
        public Value GetGlobal(string varName)
        {
            if (!_globals.TryGetValue(varName, out var value))
                throw new KeyNotFoundException($"全局变量未定义: {varName}");

            return value;
        }

        /// <summary>
        /// 检查全局变量是否存在
        /// </summary>
        public bool HasGlobal(string varName)
        {
            return _globals.ContainsKey(varName);
        }

        /// <summary>
        /// 获取所有全局变量
        /// </summary>
        public IReadOnlyDictionary<string, Value> GetAllGlobals()
        {
            return _globals;
        }

        /// <summary>
        /// 获取全局变量个数
        /// </summary>
        public int GlobalCount => _globals.Count;

        // ===== 调用栈操作(预留) =====

        /// <summary>
        /// 推入栈帧(函数调用)
        /// </summary>
        public void PushFrame(StackFrame frame)
        {
            if (frame == null)
                throw new ArgumentNullException(nameof(frame));

            _callStack.Push(frame);
        }

        /// <summary>
        /// 弹出栈帧(函数返回)
        /// </summary>
        /// <exception cref="InvalidOperationException">调用栈为空</exception>
        public StackFrame PopFrame()
        {
            if (_callStack.Count == 0)
                throw new InvalidOperationException("调用栈为空");
            return _callStack.Pop();
        }

        /// <summary>
        /// 获取当前栈帧
        /// </summary>
        public StackFrame? CurrentFrame => _callStack.Count > 0 ? _callStack.Peek() : null;

        /// <summary>
        /// 获取调用栈深度
        /// </summary>
        public int CallStackDepth => _callStack.Count;

        // ===== 变量访问(支持局部变量和全局变量) =====

        /// <summary>
        /// 设置变量(优先设置局部变量,如无栈帧则设置全局变量)
        /// </summary>
        public void SetVariable(string varName, Value value)
        {
            // 如果当前有活动栈帧,尝试在当前栈帧中查找
            if (CurrentFrame != null && CurrentFrame.HasLocal(varName))
            {
                // 如果局部变量已存在,更新它
                CurrentFrame.SetLocal(varName, value);
            }
            else if (CurrentFrame != null && !HasGlobal(varName))
            {
                // 如果是新变量且在函数内,创建为局部变量
                CurrentFrame.SetLocal(varName, value);
            }
            else
            {
                // 否则设置为全局变量(或更新已存在的全局变量)
                SetGlobal(varName, value);
            }
        }

        /// <summary>
        /// 获取变量(先查找局部变量,再查找全局变量)
        /// </summary>
        public Value GetVariable(string varName)
        {
            // 如果当前有活动栈帧,先在局部作用域查找
            if (CurrentFrame != null && CurrentFrame.HasLocal(varName))
            {
                return CurrentFrame.GetLocal(varName);
            }
            
            // 否则在全局作用域查找
            return GetGlobal(varName);
        }

        /// <summary>
        /// 检查变量是否存在(局部或全局)
        /// </summary>
        public bool HasVariable(string varName)
        {
            // 先检查局部,再检查全局
            if (CurrentFrame != null && CurrentFrame.HasLocal(varName))
                return true;
            
            return HasGlobal(varName);
        }

        // ===== 执行状态 =====

        /// <summary>
        /// 停止执行
        /// </summary>
        public void Stop()
        {
            IsRunning = false;
        }

        /// <summary>
        /// 软重置执行上下文（不清空全局变量）
        /// 用于在同一上下文中执行多个指令序列
        /// </summary>
        public void SoftReset()
        {
            InstructionPointer = 0;
            IsRunning = true;
            LastReturnValue = null;
            _operandStack.Clear();
            _callStack.Clear();
            // 注意：不清空 _globals
        }

        /// <summary>
        /// 完全重置执行上下文（清空所有状态和全局变量）
        /// 用于初始化新的执行环境
        /// </summary>
        public void Reset()
        {
            InstructionPointer = 0;
            IsRunning = true;
            LastReturnValue = null;
            _operandStack.Clear();
            _callStack.Clear();
            _globals.Clear();
        }

        // ===== 调试和诊断 =====

        /// <summary>
        /// 获取执行状态信息
        /// </summary>
        public string GetStatusInfo()
        {
            return $@"ExecutionContext Status:
  IP: {InstructionPointer}
  Running: {IsRunning}
  Operand Stack: {_operandStack.Count} items
  Call Stack: {_callStack.Count} frames
  Global Variables: {_globals.Count}
  Last Return Value: {LastReturnValue?.DebugInfo ?? "null"}";
        }

        /// <summary>
        /// 调试输出
        /// </summary>
        public override string ToString()
        {
            return $"ExecutionContext(IP={InstructionPointer}, OpStack={_operandStack.Count}, Globals={_globals.Count})";
        }
    }
}
